package cooperated

import (
	"fmt"

	"gddgame.cc/galaxy/common/namespaces/cooperate"
	"gddgame.cc/galaxy/common/namespaces/cooperate/structure"
	"gddgame.cc/galaxy/utils"
)

func (logic *TypeMap) Attack(info *structure.ScheduleInfo, content *cooperate.TouchScheduleContent, attack *AttackLogic) {
	instance := logic.GetDetailCache(logic, info.Target)
	//result := logic.GetPropsCache(conn, info.MapNoId, info.Target, []string{Position, Identity, Speed, MoveLockTime, AttackDistance, AttackSpeed, Health, Mode, Visible, Combat, Ignore, CrossedTime, BeCrossTime, BeCrossStartTime, CrossedItem, CrossedStartTime, BeCrossItem, Defend})
	if instance == nil {
		fmt.Println("attack props miss", info.Target)
		return
	}
	health := instance.ToInt(Health)
	if health <= 0 {
		//fmt.Println("attack health", info.Target)
		return
	}
	selfIdentity := instance.ToInt(Identity)
	attackLock, attackLockTime := instance.Attr(logic.AttackLock)
	targetMode := TargetModeDefine(instance.ToByte(TargetMode))
	combat := instance.ToBool(Combat)
	lastAttackTime := instance.ToInt64(LastAttackTime)
	attackBehavior := instance.ToBytes(AttackBehavior)
	visible := TargetVisible(instance.ToByte(Visible))
	attackDistance := instance.AttrWithId(logic.AttackDistance)
	followDistance := instance.AttrWithId(logic.FollowDistance) // 跟随距离

	if content.Move != nil {
		// 攻击参数获取
		attack.Init(attackDistance, followDistance, content.Move.LastPosition)
	} else {
		attack.Init(attackDistance, followDistance, nil)
	}

	behaviors := logic.bindBehavior(instance, attack.Behaviors, attackDistance)
	//fmt.Println("behavior", instance.Data(), behaviors[0].CoolTime)

	position := content.Position
	if position == nil || len(position) == 0 {
		position = instance.ToBytes(Position)
	}
	nextTimes := make([]int64, len(behaviors))
	minTime := info.Time
	currentTime := info.Time
	if info.Time < logic.CurrentTime() {
		minTime = logic.CurrentTime()
		currentTime = minTime
	}
	times := 0
	filter := map[int]int{}
	baseBehavior := 0
	startLoop := false
	needMove := false
	needLock := false
	triggerAttack := false
	canMove := false
	needStop := false

	isAddition := false
	if attackBehavior == nil {
		attackBehavior = []byte{}
	}
	var canBehaviors []byte
	var needReady bool
	var noTarget bool
	var self *cooperate.TouchTarget
	var target *cooperate.TouchTarget
	var parter *cooperate.TouchTarget
	var targets []*cooperate.TouchTarget

	operates := []cooperate.UpdateOperateContent{}
	var combatOperates []cooperate.UpdateOperateContent
	var clearOperates []cooperate.UpdateOperateContent
	var addOperates []cooperate.UpdateOperateContent

	//fmt.Println("attack", info.Target, position, lastAttackTime, attackLockTime, info.Time)
	if lastAttackTime > info.Time {
		minTime = lastAttackTime
		currentTime = minTime
	}
	if attackLock > 0 && int64(attackLockTime)*1000 > info.Time {
		needLock = true
	}
	if content.Move != nil {
		canMove = true
	}
	if content.Times > 0 {
		// 没有目标，没有坐标，不追击，则为追加攻击
		// 驻守防御也会如此，重新定义有次数限制的位追加攻击
		isAddition = true
		canMove = false
	}

	if !isAddition && len(attackBehavior) == 0 {
		startLoop = true
	}
	var routePositions [][]byte
	if content.Move != nil {
		routePositions = content.Move.Positions[content.Move.Index:]
	}

	self, _ = logic.getTouchInfo(instance, 0)

	target = logic.defaultTarget(logic.GetMapNoId(), content, selfIdentity, position, info.Params, info.Time, &behaviors[0])
	if target == nil && attack.CanAttack {
		targets = logic.findTarget(info, attack, position, routePositions, self)
		tmp := logic.selectTarget(targets, targetMode, selfIdentity, &behaviors[0])
		if len(tmp) > 0 {
			target = tmp[0]
		}
	}

	if target == nil {
		//fmt.Println("attack target", info.Target, position, "miss target")
	}
	if target != nil {
		//fmt.Println("attack target", info.Params, info.Target, position, target.Position, targets, target.Distance, attack.Follow, attack.FollowDistance, attackDistance)
		// 对于攻击目标处理:
		// 附加攻击或者主动攻击，不验证距离
		if target.Distance <= int(behaviors[0].Distance) || isAddition {
			content.Target = target.PropsInstance.Data()
			goto Attack
		} else if attack.Follow && (attack.FollowDistance == -1 || target.Distance <= int(attack.FollowDistance)) {
			//fmt.Println("follow attack")
			needMove = true
			// 追击
			goto Judge
		} else {
			// 可能被攻击，不能脱离战斗
			goto Empty
		}
	}
	combatOperates = logic.changeCombat(info, false)
	if combatOperates != nil {
		operates = append(operates, combatOperates...)
	}
Empty:
	// 移除攻击目标
	if !isAddition {
		clearOperates = logic.clearTarget(instance)
		if clearOperates != nil {
			operates = append(operates, clearOperates...)
			content.Target = nil
		}
	}

	if canMove {
		needMove = true
	}
	needStop = true
	goto Send
Attack:
	// 默认攻击下添加目标：移动追击时也添加
	if !isAddition {
		addOperates = logic.addTarget(instance, target)
		if addOperates != nil {
			operates = append(operates, addOperates...)
		}
	}

	// 如果意外锁定攻击，则顺时延长攻击时间，但取消附加攻击
	if needLock {
		if isAddition {
			goto Judge
		}
		// 每秒执行次，确保
		minTime += 1000
		goto Send
	}

	// 获取技能可执行时间
	for index, behavior := range behaviors {
		if _, ok := filter[behavior.Id]; ok {
			continue
		}
		filter[behavior.Id] = index
		t := int64(0)
		if behavior.NeedCool {
			t = instance.ToInt64(instance.Timer().Prop(DirectCoolPrefix, behavior.Id))
			if t == 0 {
				nextTimes[index] = info.Time
			} else {
				nextTimes[index] = t
			}
		} else {
			nextTimes[index] = 0
		}
		if index == 0 {
			baseBehavior = index
		} else if startLoop {
			attackBehavior = append(attackBehavior, utils.ToByte(index))
		}
	}
	// 本次候选列表
	canBehaviors = append([]byte{byte(baseBehavior)}, attackBehavior...)
	//fmt.Println("attack target", info.Target, canBehaviors, behaviors, filter, nextTimes)

	// 查找释放技能:
	for _, i := range canBehaviors {
		index := int(i)
		behavior := behaviors[index]
		// 相同技能共享cd，只认前一个
		v := filter[behavior.Id]
		if v != index {
			continue
		}

		if index != baseBehavior {
			t := nextTimes[index]
			if t > minTime {
				// 还未到释放时间
				continue
			}
		}
		//
		currentTargets, currentPositions := logic.findTargetRange(self, behavior.Direct, target)
		if currentTargets == nil {
			if targets == nil {
				targets = logic.findTarget(info, attack, position, routePositions, self)
			}
			currentTargets = targets
		}
		rangeAttack := currentPositions != nil

		selectTargets := logic.attackTarget(targetMode, &behavior, self, currentTargets, target, parter)
		if selectTargets == nil || len(selectTargets) == 0 {
			noTarget = true
			//fmt.Println("attack no select target", info.Target, target, currentTargets, parter)
			if !rangeAttack {
				// 节点攻击，无需目标
				continue
			}
		} else {
			noTarget = false
		}

		if index != baseBehavior {
			// 从轮训队列中移除
			attackBehavior, _ = utils.RemoveByte(attackBehavior, i)
		}

		times += 1

		// 附加攻击忽略准备时间
		if !isAddition {
			needReady = logic.readyBehavior(instance, &behavior, minTime, selectTargets, position)
		}
		// 准备后发动
		minTime += int64(behavior.ReadyTime)
		//fmt.Println("execute attack", info.From, info.Target, selectTargets, behavior.Id, minTime, position)
		logic.executeAttack(info.From, self, selectTargets, currentPositions, behavior.Id, minTime, position)
		minTime += int64(behavior.CastTime)

		coolOperates := logic.addCoolTime(instance, behavior.Direct)
		if coolOperates != nil {
			// 更新冷却时间
			if minTime-currentTime == 0 {
				// 普通攻击统一执行
				operates = append(operates, coolOperates...)
			} else {
				operateData := &cooperate.UpdateOperateData{
					Data:     *info.Target,
					Operates: coolOperates,
				}

				logic.scheduleBatchUpdateOperate2(info, operateData, minTime-info.Time)
			}
		}

		if times > 1 {
			// 一次只能执行一个非普通攻击技能
			break
		}
	}
	if times > 0 {
		triggerAttack = true
	}

	if needReady {
		// 可以添加事件处理
	}
	if minTime > info.Time && minTime > lastAttackTime {
		operates = append(operates, cooperate.UpdateOperateContent{
			Operate: cooperate.ChangeData,
			Key:     LastAttackTime,
			Value:   minTime,
		})
	}
Judge:
	//fmt.Println("attack", times, behaviors, info.Time, minTime, len(targets), noTarget, canMove)
	if times == 0 {
		if noTarget {
			if canMove {
				needMove = true
			}
			needStop = true
		}
		// 每秒执行次，确保
		minTime += 1000
	}
	// 处理技能轮训
	if !isAddition {
		if times == 1 && len(behaviors) > 1 {
			// 只释放了普通攻击，则其他技能都在冷却，重新开始技能轮训
			operates = append(operates, cooperate.UpdateOperateContent{
				Operate: cooperate.ChangeData,
				Key:     AttackBehavior,
				Value:   []byte{},
			})
		} else {
			// 保存剩余轮训技能
			operates = append(operates, cooperate.UpdateOperateContent{
				Operate: cooperate.ChangeData,
				Key:     AttackBehavior,
				Value:   attackBehavior,
			})
		}
	}
	if content.Times > 0 {
		content.Times -= 1
	}
	if content.Times == 0 {
		needStop = false
	}
Send:
	// 成功攻击，变更状态
	if triggerAttack {
		if visible != NormalTargetVisible {
			visibleOperates := logic.changeVisible(info, position, self.Data(), self.Identity, false)
			operates = append(operates, visibleOperates...)
		}
		if !combat {
			combatOperates := logic.changeCombat(info, true)
			if combatOperates != nil {
				operates = append(operates, combatOperates...)
			}
		}
	}
	// 发送前进行
	if len(operates) > 0 {
		operateData := &cooperate.UpdateOperateData{
			Data:     *info.Target,
			Operates: operates,
		}
		logic.scheduleBatchUpdateOperate2(info, operateData, 0)
	}
	if needMove {
		// 切换移动
		//fmt.Println("switch move", info.Target)
		logic.switchMove(info, content, instance, position)
		needStop = true
	}
	//if times > 0 {
	//fmt.Println("send attack", info.Target, position, times, content.Times, operates, info.Time, minTime, needStop, needMove, isAddition, triggerAttack, needLock, needReady, canMove)
	//}
	if needStop {
		//fmt.Println("stop attack", info.BaseData)
		return
	}
	builder := logic.ScheduleBuilder()
	builder.BindInfo(*info).Touch(content).Schedule(minTime, nil, info.ScheduleDelay)
}
